package com.huoshan.im.server.service;

import com.huoshan.im.server.config.ConfigHolder;
import com.huoshan.im.server.config.properties.SettingConfig;
import com.huoshan.im.server.constant.CacheConstants;
import com.huoshan.im.server.dto.UserDto;
import io.netty.channel.ChannelId;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import online.chazi.bootplus.commons.utils.MapUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 说明：作者很懒，什么都没留下
 * Created by 火山九日 on 2020-04-26 16:25
 */
@Slf4j
@Service
@AllArgsConstructor
public class UserService {

    private final RedisTemplate<String, Object> userServerMapping1RedisTemplate;
    private final RedisTemplate<String, Object> userServerMapping2RedisTemplate;
    private final RedisTemplate<String, Object> userServerMapping3RedisTemplate;

    public RedisTemplate<String, Object> getUserServerMappingRedisTemplate(long code) {
        long mod = code % 3;
        if (mod == 1) return userServerMapping1RedisTemplate;
        else if (mod == 2) return userServerMapping2RedisTemplate;
        return userServerMapping3RedisTemplate;
    }

    public void userSayHi() {
        log.debug("user say: Hi~~~~");
    }


    public void cacheUserRegisterServer(ChannelId id) {
        String chanelId = id.asLongText();
        SettingConfig.Server server = ConfigHolder.getSettingConfig().getServer();
        List<String> cacheHostList = ConfigHolder.getLocalHostList();
        List<Map<String, Object>> listValue = new ArrayList<>();
        for (String host : cacheHostList) {
            Map<String, Object> value = MapUtils.<String, Object>build()
                    .add("host", host)
                    .add("port", server.getPort());
            listValue.add(value);
        }
        log.debug("注册channel信息，{}", listValue);
        //.30分钟自动失效，不然会存在很多碎片无用的chnl:****数据
        getUserServerMappingRedisTemplate(chanelId.hashCode()).opsForValue().set("chnl:" + chanelId, listValue, Duration.ofMinutes(30));
    }

    /**
     * 为了支持多网卡，一个用户连接，会有多个server内网host
     *
     * @param id      连接通道id
     * @param userDto 用户
     */
    public void cacheUserLoginServer(ChannelId id, UserDto userDto) {
        String chanelId = id.asLongText();
        String key = "chnl:" + chanelId;
        //values 是 List<Map<String, Object>>
        Object values = getUserServerMappingRedisTemplate(chanelId.hashCode()).opsForValue().get(key);
        if (values != null) {

            //TODO 上线之后，删除user:缓存
            //变形，map：： userId-clientType===>host:port
//            getUserServerMappingRedisTemplate(userDto.getUserId()).opsForValue().set("user:" + userId, values);
//            getUserServerMappingRedisTemplate(userDto.getUserId()).opsForValue().set(hKey, mapList, CacheConstants.PUB_WEEK_EXPIRY);

            String hKey = "user-client:" + userDto.getUserId();

            getUserServerMappingRedisTemplate(userDto.getUserId()).opsForHash().put(hKey, userDto.getClientType(), values);
            getUserServerMappingRedisTemplate(userDto.getUserId()).expire(hKey, CacheConstants.PUB_WEEK_EXPIRY.getSeconds(), TimeUnit.SECONDS);

            getUserServerMappingRedisTemplate(chanelId.hashCode()).delete(key);

            //TODO 上线之后，删除user-channel:缓存
            //变形 userId-clientType===>chanelId
//            getUserServerMappingRedisTemplate(userId).opsForValue().set("user-channel:" + userId, id.asLongText());
            getUserServerMappingRedisTemplate(userDto.getUserId()).opsForValue().set("user-client-channel:" + userDto.toString(), id.asLongText(), CacheConstants.PUB_WEEK_EXPIRY);
        } else {
            log.error("服务器chnl信息为空~~！！！");
        }
    }

    /**
     * @param userDto
     * @param id
     */
    public void removeCacheUserLoginServer(UserDto userDto, ChannelId id) {

        final Object o = getUserServerMappingRedisTemplate(userDto.getUserId()).opsForValue().get("user-client-channel:" + userDto.toString());

        //判断是否资格删除
        if (o != null && !Objects.equals(o.toString(), id.asLongText())) {
            log.debug("用户ID[userDto={}]channel.id不一致", userDto.toString());
            return;
        }

//        getUserServerMappingRedisTemplate(userId).delete("user:" + userId);
//        getUserServerMappingRedisTemplate(userId).delete("user-client-channel:" + userId);
        getUserServerMappingRedisTemplate(userDto.getUserId()).delete("user-client:" + userDto.toString());
        getUserServerMappingRedisTemplate(userDto.getUserId()).delete("user-client-channel:" + userDto.toString());
        getUserServerMappingRedisTemplate(userDto.getUserId()).delete(CacheConstants.USER_LOGIN_APP_PREFIX + userDto.getUserId());
    }

    ///===========

    /**
     * @param userId
     * @param deviceId
     * @return
     */
    public void cacheUserDeviceId(long userId, String deviceId, long currentTimeMillis) {
        String key = CacheConstants.USER_LOGIN_APP_PREFIX + userId;
        getUserServerMappingRedisTemplate(userId).opsForValue().set(key, deviceId + "#" + currentTimeMillis, CacheConstants.PUB_WEEK_EXPIRY);

    }

    /**
     * @param userId
     */
    public String getUserDeviceIdCache(long userId) {
        return (String) getUserServerMappingRedisTemplate(userId).opsForValue().get(CacheConstants.USER_LOGIN_APP_PREFIX + userId);
    }

}
